from flask import Blueprint, render_template, jsonify, request, redirect, url_for, flash, send_file, make_response
from flask_login import login_user, logout_user, login_required, current_user
from app import db
from app.models import Admin, Question, Config, DrawRecord, InviteCode
from werkzeug.security import generate_password_hash
import openpyxl
from io import BytesIO
from datetime import datetime
from app.forms import LoginForm, RegisterForm
import io
import json
from werkzeug.utils import secure_filename
import os
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, SubmitField
from wtforms.validators import DataRequired, NumberRange
from sqlalchemy import or_
import random
import string
from functools import wraps
import platform
import psutil

bp = Blueprint('admin', __name__, url_prefix='/admin')

def super_admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_super_admin():
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return jsonify({'error': '权限不足'}), 403
            return redirect(url_for('admin.dashboard'))
        return f(*args, **kwargs)
    return decorated_function

@bp.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('admin.dashboard'))
    
    form = LoginForm()
    if form.validate_on_submit():
        admin = Admin.query.filter_by(username=form.username.data).first()
        if admin and admin.check_password(form.password.data):
            login_user(admin)
            next_page = request.args.get('next')
            return redirect(next_page or url_for('admin.dashboard'))
        flash('用户名或密码错误')
    return render_template('admin/login.html', form=form)

@bp.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('admin.dashboard'))
    
    form = RegisterForm()
    if form.validate_on_submit():
        # 创建新管理员
        admin = Admin(username=form.username.data, role='staff')  # 默认为工作人员角色
        admin.set_password(form.password.data)
        db.session.add(admin)
        
        # 标记邀请码为已使用
        invite_code = InviteCode.query.filter_by(code=form.invite_code.data).first()
        if invite_code:
            invite_code.is_used = True
            invite_code.used_at = datetime.utcnow()
            # 注意：此时admin.id还不存在，因为尚未提交事务
            # 我们将在提交后更新used_by字段
        
        db.session.commit()
        
        # 更新邀请码的used_by字段
        if invite_code:
            invite_code.used_by = admin.id
            db.session.commit()
        
        flash('注册成功，请登录')
        return redirect(url_for('admin.login'))
    return render_template('admin/register.html', form=form)

@bp.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('main.index'))

@bp.route('/')
@login_required
def dashboard():
    """管理后台首页"""
    questions = Question.query.all()
    draw_count = DrawRecord.query.count()
    configs = {config.key: config.value for config in Config.query.all()}
    
    # 获取系统信息
    now = datetime.now()
    
    return render_template('admin/dashboard.html',
                         questions=questions,
                         draw_count=draw_count,
                         configs=configs,
                         now=now,
                         platform_module=platform,
                         psutil_module=psutil)

@bp.route('/questions')
@login_required
@super_admin_required
def questions():
    questions = Question.query.order_by(Question.id.desc()).all()
    return render_template('admin/questions.html', questions=questions)

class ConfigForm(FlaskForm):
    questions_per_draw = IntegerField('每次抽题数量', validators=[DataRequired(), NumberRange(min=1)])
    retry_limit = IntegerField('最大重抽次数', validators=[DataRequired(), NumberRange(min=0)])
    submit = SubmitField('保存配置')

@bp.route('/config', methods=['GET', 'POST'])
@login_required
@super_admin_required
def config():
    form = ConfigForm()
    if form.validate_on_submit():
        try:
            # 更新或创建配置
            configs = {
                'questions_per_draw': str(form.questions_per_draw.data),
                'retry_limit': str(form.retry_limit.data)
            }
            
            for key, value in configs.items():
                config = Config.query.filter_by(key=key).first()
                if not config:
                    config = Config(key=key)
                    db.session.add(config)
                config.value = value
            
            db.session.commit()
            flash('配置已更新', 'success')
            return redirect(url_for('admin.config'))
            
        except Exception as e:
            flash(f'更新配置时出错: {str(e)}', 'error')
            return redirect(url_for('admin.config'))
    
    # GET method
    configs = {}
    for config in Config.query.all():
        configs[config.key] = config.value
    
    # 设置表单的默认值
    if not form.questions_per_draw.data:
        form.questions_per_draw.data = int(configs.get('questions_per_draw', 1))
    if not form.retry_limit.data:
        form.retry_limit.data = int(configs.get('retry_limit', 3))
    
    return render_template('admin/config.html', form=form, configs=configs)

@bp.route('/statistics')
@login_required
def statistics():
    # 获取所有题目
    questions = Question.query.all()
    
    # 获取所有抽题记录
    draw_records = DrawRecord.query.all()
    
    # 统计每个题目的抽取次数
    question_stats = {}
    for record in draw_records:
        question_ids = record.get_question_ids()
        for qid in question_ids:
            if qid in question_stats:
                question_stats[qid] += 1
            else:
                question_stats[qid] = 1
    
    # 整理统计结果
    stats_result = []
    for question in questions:
        stats_result.append({
            'id': question.id,
            'content': question.content,
            'draw_count': question_stats.get(question.id, 0)
        })
    
    # 按抽取次数排序
    stats_result.sort(key=lambda x: x['draw_count'], reverse=True)
    
    return render_template('admin/statistics.html', question_stats=stats_result)

@bp.route('/api/questions', methods=['POST'])
@login_required
@super_admin_required
def add_question():
    data = request.get_json()
    if not data or 'content' not in data or 'answer' not in data:
        return jsonify({'error': '缺少必要参数'}), 400
    
    question = Question(
        content=data['content'],
        answer=data['answer'],
        create_time=datetime.utcnow()
    )
    db.session.add(question)
    db.session.commit()
    
    return jsonify({
        'id': question.id,
        'content': question.content,
        'answer': question.answer,
        'create_time': question.create_time.strftime('%Y-%m-%d %H:%M:%S')
    })

@bp.route('/api/questions/<int:id>', methods=['PUT'])
@login_required
@super_admin_required
def edit_question(id):
    question = Question.query.get_or_404(id)
    data = request.get_json()
    
    if 'content' in data:
        question.content = data['content']
    if 'answer' in data:
        question.answer = data['answer']
    
    db.session.commit()
    return jsonify({
        'id': question.id,
        'content': question.content,
        'answer': question.answer
    })

@bp.route('/api/questions/<int:id>', methods=['DELETE'])
@login_required
@super_admin_required
def delete_question(id):
    question = Question.query.get_or_404(id)
    db.session.delete(question)
    db.session.commit()
    return jsonify({'message': '删除成功'})

@bp.route('/api/questions/import', methods=['POST'])
@login_required
@super_admin_required
def import_questions():
    if 'file' not in request.files:
        return jsonify({'error': '没有上传文件'}), 400
    
    file = request.files['file']
    if not file.filename.endswith('.xlsx'):
        return jsonify({'error': '只支持Excel文件'}), 400
    
    try:
        wb = openpyxl.load_workbook(file)
        ws = wb.active
        
        for row in ws.iter_rows(min_row=2):
            if row[0].value and row[1].value:
                question = Question(
                    content=row[0].value,
                    answer=row[1].value,
                    create_time=datetime.utcnow()
                )
                db.session.add(question)
        
        db.session.commit()
        return jsonify({'message': '导入成功'})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@bp.route('/api/questions/export')
@login_required
@super_admin_required
def export_questions():
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.append(['题目内容', '答案'])
    
    for question in Question.query.all():
        ws.append([question.content, question.answer])
    
    buffer = io.BytesIO()
    wb.save(buffer)
    buffer.seek(0)
    
    return send_file(
        buffer,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name='questions.xlsx'
    )

@bp.route('/api/questions/template')
@login_required
def download_import_template():
    wb = openpyxl.Workbook()
    ws = wb.active
    
    # 设置表头
    ws.append(['题目内容', '答案'])
    
    # 添加示例数据
    ws.append(['示例题目1', '示例答案1'])
    ws.append(['示例题目2', '示例答案2'])
    
    # 设置列宽
    ws.column_dimensions['A'].width = 50
    ws.column_dimensions['B'].width = 50
    
    # 添加说明
    ws['D1'] = '说明：'
    ws['D2'] = '1. 请勿修改表头'
    ws['D3'] = '2. 题目内容和答案不能为空'
    ws['D4'] = '3. 支持批量导入多道题目'
    ws['D5'] = '4. 导入时会自动跳过空行'
    
    buffer = io.BytesIO()
    wb.save(buffer)
    buffer.seek(0)
    
    return send_file(
        buffer,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name='题目导入模板.xlsx'
    )

@bp.route('/api/questions/search')
@login_required
@super_admin_required
def search_questions():
    query = request.args.get('q', '').strip()
    if not query:
        questions = Question.query.order_by(Question.id.desc()).all()
    else:
        questions = Question.query.filter(
            or_(
                Question.content.ilike(f'%{query}%'),
                Question.answer.ilike(f'%{query}%')
            )
        ).order_by(Question.id.desc()).all()
    
    return jsonify({
        'questions': [{
            'id': q.id,
            'content': q.content,
            'answer': q.answer,
            'create_time': q.create_time.strftime('%Y-%m-%d %H:%M:%S')
        } for q in questions]
    })

@bp.route('/api/questions/batch-delete', methods=['POST'])
@login_required
@super_admin_required
def batch_delete_questions():
    data = request.get_json()
    if not data or 'ids' not in data:
        return jsonify({'error': '缺少必要参数'}), 400
    
    try:
        Question.query.filter(Question.id.in_(data['ids'])).delete(synchronize_session=False)
        db.session.commit()
        return jsonify({'message': '批量删除成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@bp.route('/draw_records')
@login_required
def draw_records():
    # 获取最近抽题记录，按时间排序
    records = DrawRecord.query.order_by(DrawRecord.draw_time.desc()).all()
    
    # 获取题库
    questions = {q.id: {'content': q.content, 'answer': q.answer} for q in Question.query.all()}
    
    # 循环输出
    processed_records = []
    for record in records:
        question_ids = record.get_question_ids()
        questions_data = []
        for question_id in question_ids:
            question_data = questions.get(question_id, {})
            questions_data.append({
                'id': question_id,
                'content': question_data.get('content', ''),
                'answer': question_data.get('answer', '')
            })
        
        processed_records.append({
            'id': record.id,
            'student_id': record.student_id,
            'draw_time': record.draw_time,
            'is_redraw': record.is_redraw,
            'ip_address': record.ip_address,
            'user_agent': record.user_agent,
            'question_ids': record.question_ids,
            'questions': questions_data
        })
    
    return render_template('admin/draw_records.html', records=processed_records)

@bp.route('/api/draw_records/<int:record_id>/questions')
@login_required
def get_record_questions(record_id):
    record = DrawRecord.query.get_or_404(record_id)
    questions = Question.query.filter(Question.id.in_(record.get_question_ids())).all()
    return jsonify({
        'questions': [{
            'id': q.id,
            'content': q.content,
            'answer': q.answer
        } for q in questions]
    })

@bp.route('/invite_codes')
@login_required
@super_admin_required
def invite_codes():
    codes = InviteCode.query.order_by(InviteCode.created_at.desc()).all()
    return render_template('admin/invite_codes.html', codes=codes)

@bp.route('/invite_codes/create', methods=['POST'])
@login_required
def create_invite_code():
    try:
        code = request.form.get('code')
        if code:
            # 检查邀请码是否已存在
            if InviteCode.query.filter_by(code=code).first():
                return jsonify({'error': '邀请码已存在'}), 400
        else:
            # 生成随机邀请码
            code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
        
        invite_code = InviteCode(
            code=code,
            created_by=current_user.username
        )
        db.session.add(invite_code)
        db.session.commit()
        
        return jsonify({'message': '邀请码创建成功', 'code': code})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@bp.route('/invite_codes/<int:code_id>/delete', methods=['POST'])
@login_required
@super_admin_required
def delete_invite_code(code_id):
    try:
        code = InviteCode.query.get_or_404(code_id)
        if code.is_used:
            return jsonify({'error': '已使用的邀请码不能删除'}), 400
        
        db.session.delete(code)
        db.session.commit()
        return jsonify({'message': '邀请码删除成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@bp.route('/invite_codes/import', methods=['POST'])
@login_required
@super_admin_required
def import_invite_codes():
    if 'file' not in request.files:
        return jsonify({'error': '没有上传文件'}), 400
    
    file = request.files['file']
    if not file.filename.endswith('.xlsx'):
        return jsonify({'error': '只支持Excel文件(.xlsx)'}), 400
    
    try:
        # 读取Excel文件
        wb = openpyxl.load_workbook(file)
        ws = wb.active
        
        # 批量创建邀请码
        created_count = 0
        for row in ws.iter_rows(min_row=2):  # 跳过表头
            if row[0].value:  # 第一列是邀请码
                code = str(row[0].value).strip()
                # 检查邀请码是否已存在
                if not InviteCode.query.filter_by(code=code).first():
                    invite_code = InviteCode(
                        code=code,
                        created_by=current_user.username
                    )
                    db.session.add(invite_code)
                    created_count += 1
        
        db.session.commit()
        return jsonify({'message': f'成功导入 {created_count} 个邀请码'})
    except Exception as e:
        return jsonify({'error': f'导入失败：{str(e)}'}), 500

@bp.route('/invite_codes/export')
@login_required
@super_admin_required
def export_invite_codes():
    try:
        # 获取所有未使用的邀请码
        codes = InviteCode.query.filter_by(is_used=False).all()
        
        # 创建Excel工作簿
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = "邀请码列表"
        
        # 添加表头
        ws.append(['邀请码', '创建者', '创建时间'])
        
        # 添加数据
        for code in codes:
            ws.append([
                code.code,
                code.created_by,
                code.created_at.strftime('%Y-%m-%d %H:%M:%S')
            ])
        
        # 保存到内存中
        buffer = io.BytesIO()
        wb.save(buffer)
        buffer.seek(0)


        return send_file(
            buffer,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            as_attachment=True,
            download_name='invite_codes.xlsx'
        )
    except Exception as e:
        return jsonify({'error': f'导出失败：{str(e)}'}), 500

@bp.route('/invite_codes/template')
@login_required
def invite_codes_template():
    try:
        # 创建Excel工作簿
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = "邀请码导入模板"
        
        # 添加表头
        ws.append(['邀请码'])
        
        # 添加示例数据
        ws.append(['ABC123'])
        ws.append(['DEF456'])
        ws.append(['GHI789'])
        
        # 设置列宽
        ws.column_dimensions['A'].width = 20

        ws['D1'] = '说明：'
        ws['D2'] = '1. 请勿修改表头'
        ws['D3'] = '2. 邀请码不能为空'
        ws['D4'] = '3. 支持批量导入'
        ws['D5'] = '4. 导入时会自动跳过空行'
        # 保存到内存中
        buffer = io.BytesIO()
        wb.save(buffer)
        buffer.seek(0)
        
        return send_file(
            buffer,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            as_attachment=True,
            download_name='invite_codes_template.xlsx'
        )
    except Exception as e:
        return jsonify({'error': f'生成模板失败：{str(e)}'}), 500

@bp.route('/api/config', methods=['POST'])
@login_required
@super_admin_required
def update_config():
    data = request.get_json()
    if not data or 'key' not in data or 'value' not in data:
        return jsonify({'error': '缺少必要参数'}), 400
    
    try:
        config = Config.query.filter_by(key=data['key']).first()
        if not config:
            config = Config(key=data['key'])
            db.session.add(config)
        config.value = str(data['value'])
        db.session.commit()
        return jsonify({'message': '配置更新成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500 